package com.sl.core.engine.log;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Maps;
import com.sl.core.engine.status.ProcessExecutorCompInfo;
import com.sl.core.engine.step.impl.AbstractProcessComp;
import com.sl.core.engine.trans.ProcessInstance;
import lombok.Getter;
import lombok.Setter;
import org.apache.hop.core.logging.ILogMessage;
import org.apache.hop.core.logging.ILoggingObject;
import org.apache.hop.core.logging.LogChannel;
import org.apache.hop.core.logging.LogLevel;

import java.util.Collection;
import java.util.List;
import java.util.Map;

public class ProcessLogChannel extends LogChannel {

    @Getter
    @Setter
    private ILoggingObject hooks;

    @Getter
    @Setter
    private ILoggingObject parentHooks;


    public ProcessLogChannel(Object subject, ILoggingObject parentObject) {
        super(subject, parentObject);
        this.hooks = parentObject;
    }

    public ProcessLogChannel(Object subject, ILoggingObject parentObject, boolean gatheringMetrics, boolean forceNewLoggingEntry) {
        super(subject, parentObject, gatheringMetrics, forceNewLoggingEntry);
        if (subject instanceof ILoggingObject il) {
            this.hooks = il;
        } else {
            this.hooks = parentObject;
        }
        this.parentHooks = parentObject;
    }


    public void println(ILogMessage logMessage, LogLevel channelLogLevel) {
        if (!logMessage.getLevel().isVisible(channelLogLevel)) {
            return; // not for our eyes.
        }
        long id = Thread.currentThread().getId();
        String name = Thread.currentThread().getName();
//        String hex = HexUtil.toHex(id);
        String tid = null;
        String instanceId = null;
        if (hooks instanceof ProcessInstance processInstance) {
            tid = processInstance.getTid();
            instanceId = processInstance.getInstanceId();
        }
        if (hooks instanceof AbstractProcessComp abstractProcessComp) {
            tid = abstractProcessComp.getPipeline().getTid();
            instanceId = abstractProcessComp.getPipeline().getInstanceId();
        }
        if (logMessage instanceof ProcessLogMessage) {

            ((ProcessLogMessage) logMessage).setThreadName(name);
            ((ProcessLogMessage) logMessage).setThreadId(StrUtil.toString(id));
            ((ProcessLogMessage) logMessage).setTid(tid);
            ((ProcessLogMessage) logMessage).setInstanceId(instanceId);
            super.println(logMessage, channelLogLevel);
            return;
        }

        ProcessLogMessage processLogMessage = new ProcessLogMessage(logMessage, hooks);
        processLogMessage.setThreadId(StrUtil.toString(id));
        processLogMessage.setThreadName(name);
        processLogMessage.setTid(tid);
        processLogMessage.setInstanceId(instanceId);
        super.println(processLogMessage, channelLogLevel);
    }


    public void logFinish(String s) {
        ProcessLogMessage openSkyLogMessage = new ProcessLogMessage(s, getLogChannelId(), LogLevel.BASIC, hooks);
        println(openSkyLogMessage, LogLevel.ROWLEVEL);
    }

    public void logStatus(List<ProcessExecutorCompInfo> executorSteps) {
        ProcessLogMessage openSkyLogMessage = new ProcessLogMessage(executorSteps, getLogChannelId(), LogLevel.BASIC, hooks);
        println(openSkyLogMessage, LogLevel.ROWLEVEL);
    }

    public void logInput(Object input) {
        if (ObjectUtil.isNull(input)) {
            return;
        }
        if (input instanceof Collection<?> outoutList) {
            for (Object o : outoutList) {
                logInput(o);
            }
        } else {
            ProcessLogMessage openSkyLogMessage = new ProcessLogMessage(true, input, getLogChannelId(), LogLevel.BASIC, hooks);
            println(openSkyLogMessage, LogLevel.ROWLEVEL);
        }
    }

    public void logOutput(Object output) {
        if (ObjectUtil.isNull(output)) {
            return;
        }
        if (output instanceof Collection<?> outoutList) {
            for (Object o : outoutList) {
                logOutput(o);
            }
        } else {
            ProcessLogMessage openSkyLogMessage = new ProcessLogMessage(false, output, getLogChannelId(), LogLevel.BASIC, hooks);
            println(openSkyLogMessage, LogLevel.ROWLEVEL);
        }

    }
}
